/*
 * forecast.c
 *
 *  Created on: 2009-8-10
 *      Author: wyb
 */

#include "forecast.h"
#include "history.h"

double forecast(char *app_name) {

	struct app *app = get_app(app_name);

	if (app == NULL) {
		xengine_mysql_close();
		return 0.0;
	}

	//从数据库中获取周期
	double period = app->period;

	//从数据库中取得当前一个范围的数据
	int num = ((int) period) * MIN_FREQUENCY / 2;
	if (num < LIMIT_NUM) {
		num = LIMIT_NUM;
	}

	time_t current_time;
	struct double_array *current = get_part_history(app->id, "cpu", num,
			&current_time);

	if (period <= 0.0) {
		double current_value = current->data[current->N - 1];
		//将预测值写入数据库
		insert_forecast(app->id, "cpu", current_value, (current_time
				+ FORECAST_INTERVAL * 60));
		free(current->data);
		free(current);
		free(app);
		xengine_mysql_close();
		return current_value;
	}

	history_filter(current);

	//做fft
	struct fft_complex *current_complex = real_to_complex(current);
	struct fft_complex *current_fft_complex = fft(current_complex);
	struct fft_cosine *current_fft_cosine = complex_to_cosine(
			current_fft_complex);

	struct double_array *error_double;
	error_double = malloc(sizeof(struct double_array));
	error_double->N = current->N;
	error_double->data = malloc(error_double->N * sizeof(double));

	//计算周期成分
	double temp = compute_conine(current_fft_cosine, current->N, period, 0);
	int j;
	for (j = 1; j < current->N; j++) {
		double percent = current->data[j - 1] / temp;
		temp = compute_conine(current_fft_cosine, current->N, period, j);
		error_double->data[j] = current->data[j] - temp * percent;
	}

	int points = FORECAST_INTERVAL / HISTORY_INTERVAL;

	struct ar_model *ar = ar_AIC(error_double->N, error_double->data);
	struct double_array *error_result = compute_ar_model(current->N + points,
			ar, error_double);
	//	output_ar(ar);

	int point = 0;
	double forecast_m = 0.0;

	for (j = 1; j <= points; j++) {
		double forecast_t = current->N - 1 + j;
		double forecast = 0.0;
		double a = temp;
		double b = compute_conine(current_fft_cosine, current->N, period,
				forecast_t);
		forecast = b * current->data[current->N - 1] / a;

		forecast = forecast + error_result->data[current->N - 1 + j];
		if (forecast > forecast_m) {
			point = j;
			forecast_m = forecast;
		}
	}
	//将预测值写入数据库
	insert_forecast(app->id, "cpu", forecast_m, (current_time
			+ FORECAST_INTERVAL * 60));

	//释放资源
	free(app);
	free(current->data);
	free(current);
	free(current_complex->data);
	free(current_complex);
	free(current_fft_complex->data);
	free(current_fft_complex);
	free(current_fft_cosine->A);
	free(current_fft_cosine);
	free(error_double->data);
	free(error_double);
	free(ar->seq);
	free(ar);
	free(error_result->data);
	free(error_result);

	return forecast_m;
}
